package com.org.daniel.framework.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
//import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
//import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.ObjectUtils;

import java.time.Duration;

/**
 * Redis多数据源设置
 * @author Daniel
 */
@Configuration
public class RedisMultiSourceConfiguration {

	// redis公共配置部分
	@Value("${spring.redis.lettuce.pool.max-active}")
	private int maxActive;
	@Value("${spring.redis.lettuce.pool.max-wait}")
	private long maxWait;
	@Value("${spring.redis.lettuce.pool.max-idle}")
	private int maxIdle;
	@Value("${spring.redis.lettuce.pool.min-idle}")
	private int minIdle;
	@Value("${spring.redis.timeout}")
	private long timeout;

	// redis 多数据源master部分
	@Value("${spring.redis.master.host}")
	private String masterHost;
	@Value("${spring.redis.master.port}")
	private int masterPort;
	@Value("${spring.redis.master.password}")
	private String masterPassword;
	@Value("${spring.redis.master.database}")
	private int masterDatabase;

	// redis 多数据源second部分
	@Value("${spring.redis.second.host}")
	private String secondHost;
	@Value("${spring.redis.second.port}")
	private int secondPort;
	@Value("${spring.redis.second.password}")
	private String secondPassword;
	@Value("${spring.redis.second.database}")
	private int secondDatabase;

	@Bean(name = "redisTemplateMaster")
	public RedisTemplate redisTemplateMaster(){
		RedisStandaloneConfiguration configuration = generateConfig(masterHost, masterPort, masterPassword, masterDatabase);
		return redisTemplateSecond(configuration);
	}

	@Bean(name = "redisTemplateSecond")
	public RedisTemplate redisTemplateSecond(){
		RedisStandaloneConfiguration configuration = generateConfig(secondHost, secondPort, secondPassword, secondDatabase);
		return redisTemplateSecond(configuration);
	}

	private RedisTemplate redisTemplateSecond(RedisStandaloneConfiguration configuration){
		//* ========= 连接池通用配置 ========= *//
		GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
		genericObjectPoolConfig.setMaxTotal(maxActive);
		genericObjectPoolConfig.setMinIdle(minIdle);
		genericObjectPoolConfig.setMaxIdle(maxIdle);
		genericObjectPoolConfig.setMaxWaitMillis(maxWait);

		//* ========= jedis pool ========= *//
		/*
		JedisClientConfiguration.DefaultJedisClientConfigurationBuilder builder
				= (JedisClientConfiguration.DefaultJedisClientConfigurationBuilder) JedisClientConfiguration.builder();
		builder.connectTimeout(Duration.ofSeconds(timeout));
		builder.usePooling();
		builder.poolConfig(genericObjectPoolConfig);
		JedisConnectionFactory connectionFactory = new JedisConnectionFactory(configuration, builder.build());
		// 连接池初始化
		connectionFactory.afterPropertiesSet();
		*/

		//* ========= lettuce pool ========= *//
		LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder builder
				= LettucePoolingClientConfiguration.builder();
		builder.poolConfig(genericObjectPoolConfig);
		builder.commandTimeout(Duration.ofSeconds(timeout));
		LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(configuration, builder.build());
		connectionFactory.afterPropertiesSet();

		//* ========= 创建 template ========= *//
		return createRedisTemplate(connectionFactory);
	}

	private RedisStandaloneConfiguration generateConfig(String host, int port, String password, int database){
		//* ========= 基本配置 ========= *//
		RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
		configuration.setHostName(host);
		configuration.setPort(port);
		configuration.setDatabase(database);
		if (!ObjectUtils.isEmpty(password)){
			RedisPassword redisPassword = RedisPassword.of(password);
			configuration.setPassword(redisPassword);
		}
		return configuration;
	}

	/**
	 * json实现redisTemplate
	 * 不能添加@Bean 否则不管如何调用，connectionFactory都会是默认配置
	 * @param redisConnectionFactory redisConnectionFactory
	 * @return RedisTemplate
	 */
	private RedisTemplate createRedisTemplate(RedisConnectionFactory redisConnectionFactory){
		RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
		redisTemplate.setConnectionFactory(redisConnectionFactory);

		Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
		ObjectMapper objectMapper = new ObjectMapper();
		objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
		objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
		jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

		redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
		redisTemplate.setKeySerializer(new StringRedisSerializer());
		redisTemplate.afterPropertiesSet();
		return redisTemplate;
	}

}
